/*
 * Copyright 2008-2009 Aying.Net Powered by Fuchun.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
 * file except in compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package net.aying.util;

import java.util.Arrays;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import junit.framework.Test;
import junit.framework.TestSuite;
import junit.textui.TestRunner;

/**
 * StringUtils 字符串工具类的测试用例。
 * 
 * @author fuchun
 */
public class StringUtilsTestCase extends UtilBasedTestCase {
	
	private static final Log log = LogFactory.getLog(StringUtilsTestCase.class);

	private static final String NULL_STR = "null";
	private static final String EMPTY_STR = "";
	private static final String WHITESPACES = "    ";
	private static final String USER_INPUT = " ggfgg  ";
	private static final String USER_INPUT1 = "_ggfgg__";
	private String st1, st1_1, st1_2, st1_3, st1_4;
	private String[] alphabets = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q",
			"r", "s", "t", "u", "v", "w", "x", "y", "z" };

	private void initStringUtilsArguments() {
		st1 = "AbcdEfGhijklMnOpqrsTuvwxYz";
		st1_1 = "AbcdEfG";
		st1_2 = "abcdefg";
		st1_3 = "TuvwxYz";
		st1_4 = "tuvwxyz";
	}

	private void tearStringUtilsArguments() {
		st1 = null;
		st1_1 = null;
		st1_2 = null;
		st1_3 = null;
		st1_4 = null;
	}

	public StringUtilsTestCase(String testName) {
		super(testName);
	}

	/** @see junit.framework.TestCase#setUp() */
	public void setUp() throws Exception {
		initStringUtilsArguments();
	}

	/** @see junit.framework.TestCase#tearDown() */
	public void tearDown() throws Exception {
		tearStringUtilsArguments();
	}

	/** @see StringUtils#isNullOrEmpty(CharSequence) */
	public void test_isNullOrEmpty() throws Exception {
		assertTrue(StringUtils.isNullOrEmpty(NULL_STR));
		assertTrue(StringUtils.isNullOrEmpty(EMPTY_STR));
		assertTrue(StringUtils.isNullOrEmpty(null));
		assertFalse(StringUtils.isNullOrEmpty(st1));
	}

	/** @see StringUtils#hasText(CharSequence) */
	public void test_hasText() throws Exception {
		assertTrue(StringUtils.hasText(USER_INPUT));
		assertTrue(StringUtils.hasText(NULL_STR));
		assertFalse(StringUtils.hasText(EMPTY_STR));
		assertFalse(StringUtils.hasText(WHITESPACES));
		assertFalse(StringUtils.hasText(null));
	}

	/** @see StringUtils#hasLength(String) */
	public void test_hasLength() throws Exception {
		assertTrue(StringUtils.hasLength(NULL_STR));
		assertTrue(StringUtils.hasLength(WHITESPACES));
		assertTrue(StringUtils.hasLength(USER_INPUT));
		assertFalse(StringUtils.hasLength(EMPTY_STR));
		assertFalse(StringUtils.hasLength(null));
	}

	/** @see StringUtils#isBlank(String) */
	public void test_isBlank() throws Exception {
		assertFalse(StringUtils.isBlank(null));
		assertFalse(StringUtils.isBlank(NULL_STR));
		assertFalse(StringUtils.isBlank(EMPTY_STR));
		assertTrue(StringUtils.isBlank(WHITESPACES));
		assertFalse(StringUtils.isBlank(USER_INPUT));
	}

	/** @see StringUtils#startsWith(String) */
	public void test_startsWith() throws Exception {
		assertTrue(StringUtils.startsWith(st1, st1_1));
		// 忽略大小写
		assertTrue("st1: " + st1 + ", st1_2: " + st1_2, StringUtils.startsWith(st1, st1_2, true));
		// 大小写敏感
		assertFalse(StringUtils.startsWith(st1, st1_2));
	}

	/** @see StringUtils#endsWith(String) */
	public void test_endsWith() throws Exception {
		assertTrue("st1: " + st1 + ", st1_3: " + st1_3, StringUtils.endsWith(st1, st1_3));
		// 忽略大小写
		assertTrue(StringUtils.endsWith(st1, st1_4, true));
		assertFalse(StringUtils.endsWith(st1, st1_4));
	}

	/** @see StringUtils#containsBlank(String) */
	public void test_containsBlank() throws Exception {
		assertTrue(StringUtils.containsBlank(WHITESPACES));
		assertTrue(StringUtils.containsBlank(USER_INPUT));
		assertFalse(StringUtils.containsBlank(EMPTY_STR));
		assertFalse(StringUtils.containsBlank(NULL_STR));
	}

	/** @see StringUtils#trim(String, char...) */
	public void test_trim() throws Exception {
		assertEquals(EMPTY_STR, StringUtils.trim(WHITESPACES));
		assertEquals(USER_INPUT.trim(), StringUtils.trim(USER_INPUT));
		assertFalse(USER_INPUT.trim().equals(StringUtils.trim(USER_INPUT, '_')));
		assertEquals(USER_INPUT1, StringUtils.trim(USER_INPUT1));
		assertEquals(USER_INPUT1.replaceAll("_", ""), StringUtils.trim(USER_INPUT1, '_'));
	}

	/** @see StringUtils#trimAllBlank(String) */
	public void test_trimAllBlank() throws Exception {
		assertEquals(EMPTY_STR, StringUtils.trimAllBlank(null));
		assertEquals(EMPTY_STR, StringUtils.trimAllBlank(WHITESPACES));
		assertEquals(USER_INPUT.trim(), StringUtils.trimAllBlank(USER_INPUT));
	}

	/**
	 * @see StringUtils#trimLeft(String)
	 * @see StringUtils#trimLeft(String, char)
	 */
	public void test_trimLeft() throws Exception {
		assertEquals(EMPTY_STR, StringUtils.trimLeft(WHITESPACES));
		assertEquals(USER_INPUT.replaceAll("^(\\s|\\u00A0)+", ""), StringUtils.trimLeft(USER_INPUT));
		assertEquals(USER_INPUT1.replaceAll("^_+", ""), StringUtils.trimLeft(USER_INPUT1, '_'));
	}

	/**
	 * @see StringUtils#trimRight(String)
	 * @see StringUtils#trimRight(String, char)
	 */
	public void test_trimRight() throws Exception {
		assertEquals(EMPTY_STR, StringUtils.trimRight(WHITESPACES));
		assertEquals(USER_INPUT.replaceAll("(\\s|\\u00A0)+$", ""), StringUtils.trimRight(USER_INPUT));
		assertEquals(USER_INPUT1.replaceAll("_+$", ""), StringUtils.trimRight(USER_INPUT1, '_'));
	}

	/** @see StringUtils#length(String, String...) */
	public void test_length() throws Exception {
		String str = "a，sfjaklsjflkasdjf";
		assertEquals(19, StringUtils.length(str, StringUtils.GBK));
		assertEquals(20, StringUtils.length(str, StringUtils.UTF8));
		assertEquals(18, StringUtils.length(str));
	}

	/** @see StringUtils#isAllDigit(String) */
	public void test_isAllDigit() throws Exception {
		assertTrue(StringUtils.isAllDigit("123456789"));
		assertFalse(StringUtils.isAllDigit("12345678a"));
	}

	/** @see StringUtils#isAllLetter(String) */
	public void test_isAllLetter() throws Exception {
		assertTrue(StringUtils.isAllLetter(st1));
		assertFalse(StringUtils.isAllLetter(st1.concat("1")));
	}

	/** @see StringUtils#isDate(String) */
	public void test_isDate() throws Exception {
		assertTrue(StringUtils.isDate("2010/03/19", "yyyy/MM/dd"));
		assertTrue(StringUtils.isDate("10/03/19", "yy/mm/dd"));
		assertTrue(StringUtils.isDate("1998-09-08 19:09:08", "yyyy-MM-dd HH:mm:ss"));
		assertFalse(StringUtils.isDate("19b9801016666", "yyyyMMddhm"));
	}

	/** @see StringUtils#isEmail(String) */
	public void test_isEmail() throws Exception {
		assertTrue(StringUtils.isEmail("abcdef@a.cc"));
		assertTrue(StringUtils.isEmail("a-b_c@a.b.cc"));
		assertTrue(StringUtils.isEmail("abc@a-b-c.dd"));
		assertTrue(StringUtils.isEmail("a.b-c_d@e.ff"));
		assertFalse(StringUtils.isEmail("abc@-a.b.cc"));
		/* 开头不能是中划线、点或者下划线 */
		assertFalse(StringUtils.isEmail("-abc@ab.cc"));
		assertFalse(StringUtils.isEmail(".abc@ab.cc"));
		assertFalse(StringUtils.isEmail("_abc@ab.cc"));
		/* 不能出现连续的点、中划线或者下划线 */
		assertFalse(StringUtils.isEmail("a..bc@ab.cc"));
		assertFalse(StringUtils.isEmail("a--bc@ab.cc"));
		assertFalse(StringUtils.isEmail("a__bc@ab.cc"));
	}

	/** @see StringUtils#inArray(String, String...) */
	public void test_inArray() throws Exception {
		assertTrue(StringUtils.inArray("m", alphabets));
		assertFalse(StringUtils.inArray("2", alphabets));
	}

	/** @see StringUtils#escapeXml(String) */
	public void test_escapeXml() throws Exception {
		String source = "<div id=\"div1\"><span class='tt'>&nbsp;&nbsp;&amp;RRGGBB</span></div>";
		String changeSource = "&lt;div id=&#034;div1&#034;&gt;&lt;span class=&#039;tt&#039;&gt;&amp;nbsp;&amp;nbsp;&amp;amp;RRGGBB&lt;/span&gt;&lt;/div&gt;";
		assertEquals(changeSource, StringUtils.escapeXml(source));
	}

	/** @see StringUtils#split(String, String) */
	public void test_split() throws Exception {
		String[] st1_1_arr = { "A", "b", "c", "d", "E", "f", "G" };
		String[] result = StringUtils.split(st1_1, "");
		boolean equals = true;
		for (int i = 0, len = result.length; i < len; i++) {
			if (!result[i].equals(st1_1_arr[i])) {
				equals = false;
				break;
			}
		}
		assertTrue(equals);
	}

	/**
	 * @see StringUtils#join(String[])
	 * @see StringUtils#join(String[], String)
	 * @see StringUtils#join(java.util.Collection, String, String, String)
	 */
	public void test_join() throws Exception {
		StringBuffer buf1 = new StringBuffer();
		for (int i = 0, len = alphabets.length; i < len; i++) {
			buf1.append(alphabets[i]);
			if (i != len - 1)
				buf1.append(",");
		}
		assertEquals(buf1.toString(), StringUtils.join(alphabets));

		StringBuffer buf2 = new StringBuffer();
		for (int i = 0, len = alphabets.length; i < len; i++) {
			buf2.append(alphabets[i]);
			if (i != len - 1)
				buf2.append("_");
		}
		assertEquals(buf2.toString(), StringUtils.join(alphabets, "_"));

		StringBuffer buf3 = new StringBuffer();
		for (String s : alphabets) {
			buf3.append(s);
		}
		/* null 或者 空字符串 的分隔符是一样的效果 */
		assertEquals(buf3.toString(), StringUtils.join(alphabets, EMPTY_STR));
		assertEquals(buf3.toString(), StringUtils.join(alphabets, null));

		List<String> alphaList = Arrays.asList(alphabets);
		String pre1 = "", suf1 = "", pre2 = "_", suf2 = "_";
		StringBuffer buf4 = new StringBuffer();
		StringBuffer buf5 = new StringBuffer();
		for(int i = 0, len = alphabets.length; i < len; i++) {
			buf4.append(pre1).append(alphabets[i]).append(suf1);
			buf5.append(pre2).append(alphabets[i]).append(suf2);
			if(i != len - 1) {
				buf5.append(",");
			}
		}
		log.info(buf4.toString());
		log.info(StringUtils.join(alphaList, EMPTY_STR, pre1, suf1));
		assertEquals(buf4.toString(), StringUtils.join(alphaList, EMPTY_STR, pre1, suf1));
		log.info(buf5.toString());
		log.info(StringUtils.join(alphaList, ",", pre2, suf2));
		assertEquals(buf5.toString(), StringUtils.join(alphaList, ",", pre2, suf2));
	}
	
	/** @see StringUtils#countOccurrencesOf(String, String) */
	public void test_countOccurrencesOf() throws Exception {
		assertEquals(2, StringUtils.countOccurrencesOf(USER_INPUT, "gg"));
		assertEquals(0, StringUtils.countOccurrencesOf(USER_INPUT, EMPTY_STR));
		assertEquals(1, StringUtils.countOccurrencesOf(USER_INPUT, "f"));
		assertEquals(3, StringUtils.countOccurrencesOf(USER_INPUT, " "));
	}
	
	/** @see StringUtils#quote(String, String) */
	public void test_quote() throws Exception {
		String stest = StringUtils.join(alphabets, "");
		assertEquals("\"" + stest + "\"", StringUtils.quote(stest, "\""));
		assertEquals("'" + stest + "'", StringUtils.quote(stest, "'"));
		assertEquals("**" + stest + "**", StringUtils.quote(stest, "**"));
		assertEquals("\"" + stest + "\"", StringUtils.quote(stest, ""));
		assertEquals("\"" + stest + "\"", StringUtils.quote(stest, null));
		assertEquals("\"" + stest + "\"", StringUtils.quote(stest, "    "));
	}
	
	/** @see StringUtils#truncate(String, String, int, String...) */
	public void test_truncate() throws Exception {
		String stest = "乱七八糟   [luan qi ba zao] Pinyin : at sixes and sevens; " +
				"in great confusion; in a muck; in a clutter";
		/* 原文四个汉字，使用GBK编码模式计算时，比 length 方法计算的长度多4个，加上默认的后缀 3个字符，总共多7个。 
		 * 而使用UTF8编码模式计算时，比 length 方法计算的长度多8个，加上默认的后缀3个字符，总共多11个。
		 * 将后缀设为空字符串时，则就是汉字多出来的字符数。
		 */
		assertEquals(stest.substring(0, 53).concat("..."), StringUtils.truncate(stest, StringUtils.GBK, 60));
		assertEquals(stest.substring(0, 53).concat("..."), StringUtils.truncate(stest, StringUtils.UTF8, 64));
		assertEquals(stest.substring(0, 53), StringUtils.truncate(stest, StringUtils.GBK, 57, ""));
		assertEquals(stest.substring(0, 53), StringUtils.truncate(stest, StringUtils.UTF8, 61, ""));
	}
	
	/** @see StringUtils#pushArray(String[], String) */
	public void test_pushArray() throws Exception {
		String[] newAlpha = StringUtils.pushArray(alphabets, "abc");
		assertEquals(newAlpha[newAlpha.length - 1], "abc");
		assertEquals(alphabets.length, newAlpha.length - 1);
	}
	
	/** @see StringUtils#unionArray(String[], String[]) */
	public void test_unionArray() throws Exception {
		String[] alphabets2 = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
		String[] newAlpha = new String[alphabets.length + alphabets2.length];
		for(int i = 0, len = alphabets.length; i < len; i++) {
			newAlpha[i] = alphabets[i];
		}
		for(int i = alphabets.length, len = alphabets.length + alphabets2.length; i < len; i++) {
			newAlpha[i] = alphabets2[i - alphabets.length];
		}
		String[] newAlpha2 = StringUtils.unionArray(alphabets, alphabets2);
		for(int i = 0, len = newAlpha.length; i < len; i++) {
			assertEquals(newAlpha[i], newAlpha2[i]);
		}
	}
	
	/** @see StringUtils#mergeArray(String[], String[]) */
	public void test_mergeArray() throws Exception {
		String[] alphabets2 = { "0", "a", null, "b", "4", "c", "6", "d", "8", "e" };
		String[] newAlpha1 = StringUtils.mergeArray(alphabets, alphabets2);
		List<String> list = GenericUtils.getList();
		list.addAll(Arrays.asList(alphabets));
		for(String s : alphabets2) {
			if(!list.contains(s)) {
				list.add(s);
			}
		}
		String[] newAlpha2 = list.toArray(new String[list.size()]);
		assertEquals(newAlpha1.length, newAlpha2.length);
		for(int i = 0, len = newAlpha2.length; i < len; i++) {
			assertEquals(newAlpha1[i], newAlpha2[i]);
		}
		newAlpha1 = StringUtils.mergeArray(alphabets, new String[0]);
		assertEquals(alphabets.length, newAlpha1.length);
	}
	
	/** @see StringUtils#removeDuplicateStrings(String[]) */
	public void test_removeDuplicateStrings() throws Exception {
		String[] alphas = { "a", "a", "b", "b", "c", "c", "d", "f", null };
		String[] target = { "a", "b", "c", "d", "f", null };
		String[] result = StringUtils.removeDuplicateStrings(alphas);
		assertEquals(result.length, target.length);
		System.out.println(StringUtils.join(result));
		for(int i = 0, len = target.length; i < len; i++) {
			assertEquals(result[i], target[i]);
		}
	}

	public static Test suite() {
		return new TestSuite(StringUtilsTestCase.class);
	}

	public static void main(String[] args) {
		TestRunner.run(suite());
	}
}
